package impl

import (
	"context"
	"errors"
	"gitee.com/kordar/layuiadmin/admin/enums"
	admin "gitee.com/kordar/layuiadmin/admin/form"
	model "gitee.com/kordar/layuiadmin/admin/models"
	"gitee.com/kordar/layuiadmin/admin/repository"
	"gitee.com/kordar/layuiadmin/admin/vo"
	"gitee.com/kordar/layuiadmin/reader"
	"github.com/gin-gonic/gin"
	"github.com/kordar/gocfg"
	"github.com/kordar/gocrud"
	gocrudgorm "github.com/kordar/gocrud-gorm"
	logger "github.com/kordar/gologger"
	"gorm.io/gorm"
)

type AdminServiceImpl struct {
	*gocrud.CommonResourceService
	db    *gorm.DB
	repos *repository.AdminRepository
}

func NewAdminService(db *gorm.DB, repos *repository.AdminRepository) *AdminServiceImpl {
	return &AdminServiceImpl{db: db, repos: repos}
}

func (service AdminServiceImpl) ResourceName() string {
	return "admin"
}

func (service AdminServiceImpl) Register(form admin.RegisterForm) bool {
	return service.repos.Register(form.Username, form.Phone, form.Password)
}

func (service AdminServiceImpl) ResetPassword(form admin.ResetPasswordForm, admin model.SysAdmin) bool {
	if admin.Type == model.TypeOrdinary && int64(form.Id) != admin.ID {
		return false
	}
	return service.repos.ResetPassword(int64(form.Id), form.Password)
}

func (service AdminServiceImpl) Login(form admin.LoginForm) (model.SysAdmin, error) {
	return service.repos.Login(form.Username, form.Password)
}

func (service AdminServiceImpl) Search(body gocrud.SearchBody) gocrud.SearchVO {
	searchBody := gocrudgorm.NewGormSearchBody(body)
	db := searchBody.GormQuery(service.db, nil).Model(&model.SysAdmin{})
	queryReader := reader.NewQueryReader(db, int(body.Page), int(body.PageSize))
	var adminVOS []*vo.SysAdminVO
	return queryReader.SearchVO(&adminVOS, nil)
}

func (service AdminServiceImpl) SearchOne(body gocrud.SearchBody) gocrud.SearchOneVO {
	if body.Conditions == nil || len(body.Conditions) == 0 {
		return gocrud.NewSearchOneVO(map[string]string{})
	}
	searchBody := gocrudgorm.NewGormSearchBody(body)
	sysAdmin := model.SysAdmin{}
	tx := searchBody.GormQuery(service.db, nil).First(&sysAdmin)
	if tx.Error != nil {
		return gocrud.NewSearchOneVO(map[string]string{})
	}

	return gocrud.NewSearchOneVO(map[string]interface{}{
		"id":          sysAdmin.ID,
		"username":    sysAdmin.Username,
		"password":    sysAdmin.Password,
		"phone":       sysAdmin.Phone,
		"status":      sysAdmin.Status,
		"type":        sysAdmin.Type,
		"create_time": sysAdmin.CreateTime.Format("2006-01-02 15:04:05"),
		"update_time": sysAdmin.UpdateTime.Format("2006-01-02 15:04:05"),
	})
}

func (service AdminServiceImpl) Remove(body gocrud.RemoveBody) error {
	removeBody := gocrudgorm.NewGormRemoveBody(body)
	tx, err := removeBody.GormQuerySafe(service.db, nil)
	if err != nil {
		return err
	}

	sysAdmin := model.SysAdmin{}
	err = tx.First(&sysAdmin).Error
	if err != nil {
		return err
	}

	ctx := body.Ctx().(*gin.Context)
	user := ctx.MustGet(enums.AdminKey).(model.SysAdmin)
	if user.ID == sysAdmin.ID {
		logger.Infof("User %d is banned for trying to delete himself!", user.ID)
		return errors.New("admins cannot delete themselves")
	}

	if user.Type == model.TypeOrdinary && sysAdmin.Type == model.TypeSuper {
		return errors.New("super admins cannot delete themselves")
	}

	return tx.Delete(&sysAdmin).Error
}

func (service AdminServiceImpl) Edit(body gocrud.EditorBody) error {
	ctx := body.Ctx().(*gin.Context)
	user := ctx.MustGet(enums.AdminKey).(model.SysAdmin)
	if user.Type == model.TypeOrdinary {
		return errors.New("ordinary users are prohibited from operating")
	}
	return body.Updates(&model.SysAdmin{}, service.db.Select("*"), nil)
}

func (service AdminServiceImpl) Configs(ctx context.Context) map[string]interface{} {
	return map[string]interface{}{
		"admin-state": gocfg.GetSection("dict.admin-status"),
		"admin-type":  gocfg.GetSection("dict.admin-type"),
	}
}
